package com.boboPlanet.service;

import com.boboPlanet.comm.context.BusinessStartTimeContext;
import com.boboPlanet.comm.exception.BusinessException;
import com.boboPlanet.comm.result.ResponseResult;
import com.boboPlanet.comm.utils.AutoGenerateIds;
import com.boboPlanet.dao.GatewayMapper;
import com.boboPlanet.entity.po.AllowPathPo;
import com.boboPlanet.entity.po.GatewayPo;
import com.boboPlanet.entity.vo.AllowPathVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.*;

/**
 * @Description: TODO 网关配置实现类
 * @Author: mis_wu
 * @Date: 2022/7/10
 **/
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
@RefreshScope
public class GatewayService implements ApplicationEventPublisherAware {

    /**
     * 路由类型
     */
    private static final String ROUTE_TYPE = "0";

    private ApplicationEventPublisher publisher;

    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;

    @Autowired
    private GatewayMapper gatewayMapper;


    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }

    public void loadAllRoutes(){
        List<GatewayPo> allGatewayConfig = gatewayMapper.getAllGatewayConfig();
        for (GatewayPo allConfig : allGatewayConfig) {
            log.info("网关路由配置:{}",allConfig);
            loadRoute(allConfig);
        }
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
    }

    /**
     * https://blog.csdn.net/z_z_k/article/details/111313391
     * @param gatewayEntity gatewayEntity
     */
    public void loadRoute(GatewayPo gatewayEntity){
        RouteDefinition definition = new RouteDefinition();
        Map<String, String> predicateParams = new HashMap<>(8);
        List<PredicateDefinition> predicateDefinitionList = new ArrayList<>();
        Map<String, String> filterParams = new HashMap<>(8);
        FilterDefinition filterDefinition = new FilterDefinition();
        URI uri = null;
        //ROUTE_TYPE写在equals()前面,防止空指针
        if (ROUTE_TYPE.equals(gatewayEntity.getRouteType())){
            //如果为0,从注册中心获取服务地址
            uri = UriComponentsBuilder.fromUriString("lb://"+gatewayEntity.getRouteUrl()+"/").build().toUri();
        }else {
            uri = UriComponentsBuilder.fromHttpUrl(gatewayEntity.getRouteUrl()).build().toUri();
        }
        //定义路由唯一id
        definition.setId(gatewayEntity.getRouteId());

        //断言配置
        PredicateDefinition predicate = new PredicateDefinition();
        //断言名称/规则
        predicate.setName(gatewayEntity.getPredicatesType());
        //断言值,定义路由转发
        String[] splitValue = gatewayEntity.getPredicatesValue().split(",");
        for (int i = 0; i < splitValue.length; i++) {
            if (i == 0){
                predicateParams.put("pattern",splitValue[0]);
            }else {
                predicateParams.put("pattern"+i,splitValue[i]);
            }
        }
        log.info("predicateParams value:{}",predicateParams);
        predicate.setArgs(predicateParams);

        //定义过滤规则,名称固定,路径去前缀
        filterDefinition.setName(gatewayEntity.getFilterName());
        filterParams.put("_genkey_0",gatewayEntity.getFilterValue());
        filterDefinition.setArgs(filterParams);
        definition.setPredicates(Collections.singletonList(predicate));
        definition.setFilters(Collections.singletonList(filterDefinition));
        definition.setUri(uri);
        routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        //放在循环之后监听,否则报错
//        this.publisher.publishEvent(new RefreshRoutesEvent(this));
    }

    /**
     * 添加网关配置
     * @param gatewayPo po
     * @return boolean
     */
    public ResponseResult<Boolean> insertGatewayConfig(GatewayPo gatewayPo){

        //先不校验是否存在routeId
//        Integer count = gatewayMapper.getGatewayConfigByRouteId(gatewayPo.getRouteId());

        gatewayPo.setId(AutoGenerateIds.getGenerateId());
        String predicateValue = String.join(",", gatewayPo.getPredicatesValueArr());
        gatewayPo.setPredicatesValue(predicateValue);
        log.info("添加配置参数:{}",gatewayPo);
        Boolean result = gatewayMapper.insertGatewayConfig(gatewayPo);
        if (result){
            //新增路由规则后重新读取
            loadAllRoutes();
        }
        return ResponseResult.isSuccess(result);
    }


    public ResponseResult<List<GatewayPo>> getAllGateConfig(){
        List<GatewayPo> allGatewayConfig = gatewayMapper.getAllGatewayConfig();
        return ResponseResult.isSuccess(allGatewayConfig);
    }

    /**
     * 分页查询所有允许通过的路径
     * @param param param
     * @param page page
     * @param pageSize pageSize
     * @return AllowPathVo
     */
    public ResponseResult<List<AllowPathVo>> getAllAllowPath(String param, Integer page, Integer pageSize){
        //gatewayGlobalFilter.initGlobalFilter();
        page = (page - 1) * pageSize; //重新计算
        List<AllowPathVo> allAllowPath = gatewayMapper.getAllAllowPath(param, page, pageSize);
        return ResponseResult.isSuccess(allAllowPath);
    }

    /**
     * 添加 filter 允许通过的路由
     * @param path path
     * @return Boolean
     */
    public Boolean addAllowPath(String path){
        if (StringUtils.isEmpty(path)){
            throw BusinessException.build("路径不允许为空");
        }
        AllowPathPo allowPathPo = new AllowPathPo();
        allowPathPo.setPathId(AutoGenerateIds.getGenerateId());
        allowPathPo.setAllowPath(path);
        //LoginUserContext.getLoginUserInfo().getUsername()
        allowPathPo.setOperationPeople("admin");
        allowPathPo.setOperatorTime(BusinessStartTimeContext.getTime());
        allowPathPo.setVersion(0);
        Boolean result = gatewayMapper.addAllowPath(allowPathPo);
        if (result){
            //gatewayGlobalFilter.initGlobalFilter();
        }
        return result;
    }

}
